package functional_test

// 在scala当中，函数是一等公民，像变量一样，既可以作为函数的参数使用，也可以将函数赋值给一个变量，
// 函数的创建不用依赖于类或者对象，而在java当中，函数的创建则要依赖于类、抽象类或者接口
object FunctionalTest {
  def main(args: Array[String]): Unit = {
    print(fbn(6))
    val m = new Monster
    updateMonster(1, m)
    println("monster.name=" + m.name)
    // 一个或多个参数，可变参数要放在后面
    sum(1, 2, 3, 4)
    // 懒惰函数
    // lazy不能够修饰var类型的变量
    // 不但是在调用函数时加了lazy会导致函数的执行被推迟，我们在声明一个变量时，如果给声明了lazy，那么变量值的分配
    // 也会推迟
    lazy val l = 10
    lazy val res = sum2(10 ,20)
    println("res=" + res)
  }

  def fbn(n: Int): Int = {
    if (n == 1 || n == 2) 1 else fbn(n - 1) + fbn(n - 2)
  }

  // 参数类型和返回值类型可以是值或者是引用
  def updateMonster(n: Int, monster: Monster): Monster = {
    print("n=" + n)
    monster.name = "阿牛-" + n
    monster
  }

  // 即使有return依然返回Nothing
  // scala函数的形参默认是val的，因此不能在函数中进行修改
  def test2(n: Int) = {
//    n = 1 // it's error
//    if (n > 10) return 1 else return 0
    // 如果明确函数无返回值或不确定返回值类型，那么返回值类型可以省略（或声明位Any）
    if (n > 10) "hello" else 100
  }
  // 可变参数
  def sum(n1: Int, args: Int*) = {
    var res = n1
    for (item <- args) {
      res += item
    }
    res
  }
  // 惰性函数
  def sum2(n1: Int, n2: Int) = {
    n1 + n2
  }
}
// 为了保证线程安全和效率，内存存储的类型为val
// 架构完成两个工作，第一制定一种范式，按照这种范式去开发，二充分利用缓存
// 堆区，声明周期更长，被别人引用
// 1. 在编译器的底层，当执行一个函数/方法时，就会开辟一个新的方法栈
// 2. 每个栈的空间是相互独立的，数据也是独立的
// 当一个函数执行完毕，或者遇到return，就会返回，遵守谁调用，就将结果返回给谁，同时当函数执行完毕或者返回时，
// 该函数栈本身也会被系统销毁

// hashcode去看地址，但是不是真正的地址
class Monster {
  var name: String = "牛魔王"
}
// has return need return type
// 递归函数未执行之前是无法推断出来结果类型的，在使用时必须有明确的返回值类型